home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / SV_SAVE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  37.6 KB  |  1,757 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** sv_save.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: sv_save.c,v $
  7. //** $Revision: 1.36 $
  8. //** $Date: 95/10/17 00:10:02 $
  9. //** $Author: bgokey $
  10. //**
  11. //**************************************************************************
  12.  
  13. // HEADER FILES ------------------------------------------------------------
  14.  
  15. #include "h2def.h"
  16. #include "p_local.h"
  17.  
  18. // MACROS ------------------------------------------------------------------
  19.  
  20. #define MAX_TARGET_PLAYERS 512
  21. #define MOBJ_NULL -1
  22. #define MOBJ_XX_PLAYER -2
  23. #define GET_BYTE (*SavePtr.b++)
  24. #define GET_WORD (*SavePtr.w++)
  25. #define GET_LONG (*SavePtr.l++)
  26. #define MAX_MAPS 99
  27. #define BASE_SLOT 6
  28. #define REBORN_SLOT 7
  29. #define REBORN_DESCRIPTION "TEMP GAME"
  30. #define MAX_THINKER_SIZE 256
  31.  
  32. // TYPES -------------------------------------------------------------------
  33.  
  34. typedef enum
  35. {
  36.     ASEG_GAME_HEADER = 101,
  37.     ASEG_MAP_HEADER,
  38.     ASEG_WORLD,
  39.     ASEG_POLYOBJS,
  40.     ASEG_MOBJS,
  41.     ASEG_THINKERS,
  42.     ASEG_SCRIPTS,
  43.     ASEG_PLAYERS,
  44.     ASEG_SOUNDS,
  45.     ASEG_MISC,
  46.     ASEG_END
  47. } gameArchiveSegment_t;
  48.  
  49. typedef enum
  50. {
  51.     TC_NULL,
  52.     TC_MOVE_CEILING,
  53.     TC_VERTICAL_DOOR,
  54.     TC_MOVE_FLOOR,
  55.     TC_PLAT_RAISE,
  56.     TC_INTERPRET_ACS,
  57.     TC_FLOOR_WAGGLE,
  58.     TC_LIGHT,
  59.     TC_PHASE,
  60.     TC_BUILD_PILLAR,
  61.     TC_ROTATE_POLY,
  62.     TC_MOVE_POLY,
  63.     TC_POLY_DOOR
  64. } thinkClass_t;
  65.  
  66. typedef struct
  67. {
  68.     thinkClass_t tClass;
  69.     think_t thinkerFunc;
  70.     void (*mangleFunc)();
  71.     void (*restoreFunc)();
  72.     size_t size;
  73. } thinkInfo_t;
  74.  
  75. typedef struct
  76. {
  77.     thinker_t thinker;
  78.     sector_t *sector;
  79. } ssthinker_t;
  80.  
  81. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  82.  
  83. void P_SpawnPlayer(mapthing_t *mthing);
  84.  
  85. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  86.  
  87. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  88.  
  89. static void ArchiveWorld(void);
  90. static void UnarchiveWorld(void);
  91. static void ArchivePolyobjs(void);
  92. static void UnarchivePolyobjs(void);
  93. static void ArchiveMobjs(void);
  94. static void UnarchiveMobjs(void);
  95. static void ArchiveThinkers(void);
  96. static void UnarchiveThinkers(void);
  97. static void ArchiveScripts(void);
  98. static void UnarchiveScripts(void);
  99. static void ArchivePlayers(void);
  100. static void UnarchivePlayers(void);
  101. static void ArchiveSounds(void);
  102. static void UnarchiveSounds(void);
  103. static void ArchiveMisc(void);
  104. static void UnarchiveMisc(void);
  105. static void SetMobjArchiveNums(void);
  106. static void RemoveAllThinkers(void);
  107. static void MangleMobj(mobj_t *mobj);
  108. static void RestoreMobj(mobj_t *mobj);
  109. static int GetMobjNum(mobj_t *mobj);
  110. static void SetMobjPtr(int *archiveNum);
  111. static void MangleSSThinker(ssthinker_t *sst);
  112. static void RestoreSSThinker(ssthinker_t *sst);
  113. static void RestoreSSThinkerNoSD(ssthinker_t *sst);
  114. static void MangleScript(acs_t *script);
  115. static void RestoreScript(acs_t *script);
  116. static void RestorePlatRaise(plat_t *plat);
  117. static void RestoreMoveCeiling(ceiling_t *ceiling);
  118. static void AssertSegment(gameArchiveSegment_t segType);
  119. static void ClearSaveSlot(int slot);
  120. static void CopySaveSlot(int sourceSlot, int destSlot);
  121. static void CopyFile(char *sourceName, char *destName);
  122. static boolean ExistingFile(char *name);
  123. static void OpenStreamOut(char *fileName);
  124. static void CloseStreamOut(void);
  125. static void StreamOutBuffer(void *buffer, int size);
  126. static void StreamOutByte(byte val);
  127. static void StreamOutWord(unsigned short val);
  128. static void StreamOutLong(unsigned int val);
  129.  
  130. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  131.  
  132. extern int ACScriptCount;
  133. extern byte *ActionCodeBase;
  134. extern acsInfo_t *ACSInfo;
  135.  
  136. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  137.  
  138. char *SavePath;
  139.  
  140. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  141.  
  142. static int MobjCount;
  143. static mobj_t **MobjList;
  144. static int **TargetPlayerAddrs;
  145. static int TargetPlayerCount;
  146. static byte *SaveBuffer;
  147. static boolean SavingPlayers;
  148. static union
  149. {
  150.     byte *b;
  151.     short *w;
  152.     int *l;
  153. } SavePtr;
  154. static FILE *SavingFP;
  155.  
  156. // This list has been prioritized using frequency estimates
  157. static thinkInfo_t ThinkerInfo[] =
  158. {
  159.     {
  160.         TC_MOVE_FLOOR,
  161.         T_MoveFloor,
  162.         MangleSSThinker,
  163.         RestoreSSThinker,
  164.         sizeof(floormove_t)
  165.     },
  166.     {
  167.         TC_PLAT_RAISE,
  168.         T_PlatRaise,
  169.         MangleSSThinker,
  170.         RestorePlatRaise,
  171.         sizeof(plat_t)
  172.     },
  173.     {
  174.         TC_MOVE_CEILING,
  175.         T_MoveCeiling,
  176.         MangleSSThinker,
  177.         RestoreMoveCeiling,
  178.         sizeof(ceiling_t)
  179.     },
  180.     {
  181.         TC_LIGHT,
  182.         T_Light,
  183.         MangleSSThinker,
  184.         RestoreSSThinkerNoSD,
  185.         sizeof(light_t)
  186.     },
  187.     {
  188.         TC_VERTICAL_DOOR,
  189.         T_VerticalDoor,
  190.         MangleSSThinker,
  191.         RestoreSSThinker,
  192.         sizeof(vldoor_t)
  193.     },
  194.     {
  195.         TC_PHASE,
  196.         T_Phase,
  197.         MangleSSThinker,
  198.         RestoreSSThinkerNoSD,
  199.         sizeof(phase_t)
  200.     },
  201.     {
  202.         TC_INTERPRET_ACS,
  203.         T_InterpretACS,
  204.         MangleScript,
  205.         RestoreScript,
  206.         sizeof(acs_t)
  207.     },
  208.     {
  209.         TC_ROTATE_POLY,
  210.         T_RotatePoly,
  211.         NULL,
  212.         NULL,
  213.         sizeof(polyevent_t)
  214.     },
  215.     {
  216.         TC_BUILD_PILLAR,
  217.         T_BuildPillar,
  218.         MangleSSThinker,
  219.         RestoreSSThinker,
  220.         sizeof(pillar_t)
  221.     },
  222.     {
  223.         TC_MOVE_POLY,
  224.         T_MovePoly,
  225.         NULL,
  226.         NULL,
  227.         sizeof(polyevent_t)
  228.     },
  229.     {
  230.         TC_POLY_DOOR,
  231.         T_PolyDoor,
  232.         NULL,
  233.         NULL,
  234.         sizeof(polydoor_t)
  235.     },
  236.     {
  237.         TC_FLOOR_WAGGLE,
  238.         T_FloorWaggle,
  239.         MangleSSThinker,
  240.         RestoreSSThinker,
  241.         sizeof(floorWaggle_t)
  242.     },
  243.     { // Terminator
  244.         TC_NULL, NULL, NULL, NULL, 0
  245.     }
  246. };
  247.  
  248. // CODE --------------------------------------------------------------------
  249.  
  250. //==========================================================================
  251. //
  252. // SV_SaveGame
  253. //
  254. //==========================================================================
  255.  
  256. void SV_SaveGame(int slot, char *description)
  257. {
  258.     char fileName[100];
  259.     char versionText[HXS_VERSION_TEXT_LENGTH];
  260.  
  261.     // Open the output file
  262.     sprintf(fileName, "%shex6.hxs", SavePath);
  263.     OpenStreamOut(fileName);
  264.  
  265.     // Write game save description
  266.     StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH);
  267.  
  268.     // Write version info
  269.     memset(versionText, 0, HXS_VERSION_TEXT_LENGTH);
  270.     strcpy(versionText, HXS_VERSION_TEXT);
  271.     StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH);
  272.  
  273.     // Place a header marker
  274.     StreamOutLong(ASEG_GAME_HEADER);
  275.  
  276.     // Write current map and difficulty
  277.     StreamOutByte(gamemap);
  278.     StreamOutByte(gameskill);
  279.  
  280.     // Write global script info
  281.     StreamOutBuffer(WorldVars, sizeof(WorldVars));
  282.     StreamOutBuffer(ACSStore, sizeof(ACSStore));
  283.  
  284.     ArchivePlayers();
  285.  
  286.     // Place a termination marker
  287.     StreamOutLong(ASEG_END);
  288.  
  289.     // Close the output file
  290.     CloseStreamOut();
  291.  
  292.     // Save out the current map
  293.     SV_SaveMap(true); // true = save player info
  294.  
  295.     // Clear all save files at destination slot
  296.     ClearSaveSlot(slot);
  297.  
  298.     // Copy base slot to destination slot
  299.     CopySaveSlot(BASE_SLOT, slot);
  300. }
  301.  
  302. //==========================================================================
  303. //
  304. // SV_SaveMap
  305. //
  306. //==========================================================================
  307.  
  308. void SV_SaveMap(boolean savePlayers)
  309. {
  310.     char fileName[100];
  311.  
  312.     SavingPlayers = savePlayers;
  313.  
  314.     // Open the output file
  315.     sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
  316.     OpenStreamOut(fileName);
  317.  
  318.     // Place a header marker
  319.     StreamOutLong(ASEG_MAP_HEADER);
  320.  
  321.     // Write the level timer
  322.     StreamOutLong(leveltime);
  323.  
  324.     // Set the mobj archive numbers
  325.     SetMobjArchiveNums();
  326.  
  327.     ArchiveWorld();
  328.     ArchivePolyobjs();
  329.     ArchiveMobjs();
  330.     ArchiveThinkers();
  331.     ArchiveScripts();
  332.     ArchiveSounds();
  333.     ArchiveMisc();
  334.  
  335.     // Place a termination marker
  336.     StreamOutLong(ASEG_END);
  337.  
  338.     // Close the output file
  339.     CloseStreamOut();
  340. }
  341.  
  342. //==========================================================================
  343. //
  344. // SV_LoadGame
  345. //
  346. //==========================================================================
  347.  
  348. void SV_LoadGame(int slot)
  349. {
  350.     int i;
  351.     char fileName[100];
  352.     player_t playerBackup[MAXPLAYERS];
  353.     mobj_t *mobj;
  354.  
  355.     // Copy all needed save files to the base slot
  356.     if(slot != BASE_SLOT)
  357.     {
  358.         ClearSaveSlot(BASE_SLOT);
  359.         CopySaveSlot(slot, BASE_SLOT);
  360.     }
  361.  
  362.     // Create the name
  363.     sprintf(fileName, "%shex6.hxs", SavePath);
  364.  
  365.     // Load the file
  366.     M_ReadFile(fileName, &SaveBuffer);
  367.  
  368.     // Set the save pointer and skip the description field
  369.     SavePtr.b = SaveBuffer+HXS_DESCRIPTION_LENGTH;
  370.  
  371.     // Check the version text
  372.     if(strcmp(SavePtr.b, HXS_VERSION_TEXT))
  373.     { // Bad version
  374.         return;
  375.     }
  376.     SavePtr.b += HXS_VERSION_TEXT_LENGTH;
  377.  
  378.     AssertSegment(ASEG_GAME_HEADER);
  379.  
  380.     gameepisode = 1;
  381.     gamemap = GET_BYTE;
  382.     gameskill = GET_BYTE;
  383.  
  384.     // Read global script info
  385.     memcpy(WorldVars, SavePtr.b, sizeof(WorldVars));
  386.     SavePtr.b += sizeof(WorldVars);
  387.     memcpy(ACSStore, SavePtr.b, sizeof(ACSStore));
  388.     SavePtr.b += sizeof(ACSStore);
  389.  
  390.     // Read the player structures
  391.     UnarchivePlayers();
  392.  
  393.     AssertSegment(ASEG_END);
  394.  
  395.     Z_Free(SaveBuffer);
  396.  
  397.     // Save player structs
  398.     for(i = 0; i < MAXPLAYERS; i++)
  399.     {
  400.         playerBackup[i] = players[i];
  401.     }
  402.  
  403.     // Load the current map
  404.     SV_LoadMap();
  405.  
  406.     // Don't need the player mobj relocation info for load game
  407.     Z_Free(TargetPlayerAddrs);
  408.  
  409.     // Restore player structs
  410.     inv_ptr = 0;
  411.     curpos = 0;
  412.     for(i = 0; i < MAXPLAYERS; i++)
  413.     {
  414.         mobj = players[i].mo;
  415.         players[i] = playerBackup[i];
  416.         players[i].mo = mobj;
  417.         if(i == consoleplayer)
  418.         {
  419.             players[i].readyArtifact = players[i].inventory[inv_ptr].type;
  420.         }
  421.     }
  422. }
  423.  
  424. //==========================================================================
  425. //
  426. // SV_UpdateRebornSlot
  427. //
  428. // Copies the base slot to the reborn slot.
  429. //
  430. //==========================================================================
  431.  
  432. void SV_UpdateRebornSlot(void)
  433. {
  434.     ClearSaveSlot(REBORN_SLOT);
  435.     CopySaveSlot(BASE_SLOT, REBORN_SLOT);
  436. }
  437.  
  438. //==========================================================================
  439. //
  440. // SV_ClearRebornSlot
  441. //
  442. //==========================================================================
  443.  
  444. void SV_ClearRebornSlot(void)
  445. {
  446.     ClearSaveSlot(REBORN_SLOT);
  447. }
  448.  
  449. //==========================================================================
  450. //
  451. // SV_MapTeleport
  452. //
  453. //==========================================================================
  454.  
  455. void SV_MapTeleport(int map, int position)
  456. {
  457.     int i;
  458.     int j;
  459.     char fileName[100];
  460.     player_t playerBackup[MAXPLAYERS];
  461.     mobj_t *targetPlayerMobj;
  462.     mobj_t *mobj;
  463.     int inventoryPtr;
  464.     int currentInvPos;
  465.     boolean rClass;
  466.     boolean playerWasReborn;
  467.     boolean oldWeaponowned[NUMWEAPONS];
  468.     int oldKeys;
  469.     int oldPieces;
  470.     int bestWeapon;
  471.  
  472.     if(!deathmatch)
  473.     {
  474.         if(P_GetMapCluster(gamemap) == P_GetMapCluster(map))
  475.         { // Same cluster - save map without saving player mobjs
  476.             SV_SaveMap(false);
  477.         }
  478.         else
  479.         { // Entering new cluster - clear base slot
  480.             ClearSaveSlot(BASE_SLOT);
  481.         }
  482.     }
  483.  
  484.     // Store player structs for later
  485.     rClass = randomclass;
  486.     randomclass = false;
  487.     for(i = 0; i < MAXPLAYERS; i++)
  488.     {
  489.         playerBackup[i] = players[i];
  490.     }
  491.  
  492.     // Save some globals that get trashed during the load
  493.     inventoryPtr = inv_ptr;
  494.     currentInvPos = curpos;
  495.  
  496.     // Only SV_LoadMap() uses TargetPlayerAddrs, so it's NULLed here
  497.     // for the following check (player mobj redirection)
  498.     TargetPlayerAddrs = NULL;
  499.  
  500.     gamemap = map;
  501.     sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
  502.     if(!deathmatch && ExistingFile(fileName))
  503.     { // Unarchive map
  504.         SV_LoadMap();
  505.     }
  506.     else
  507.     { // New map
  508.         G_InitNew(gameskill, gameepisode, gamemap);
  509.  
  510.         // Destroy all freshly spawned players
  511.         for(i = 0; i < MAXPLAYERS; i++)
  512.         {
  513.             if(playeringame[i])
  514.             {
  515.                 P_RemoveMobj(players[i].mo);
  516.             }
  517.         }
  518.     }
  519.  
  520.     // Restore player structs
  521.     targetPlayerMobj = NULL;
  522.     for(i = 0; i < MAXPLAYERS; i++)
  523.     {
  524.         if(!playeringame[i])
  525.         {
  526.             continue;
  527.         }
  528.         players[i] = playerBackup[i];
  529.         P_ClearMessage(&players[i]);
  530.         players[i].attacker = NULL;
  531.         players[i].poisoner = NULL;
  532.  
  533.         if(netgame)
  534.         {
  535.             if(players[i].playerstate == PST_DEAD)
  536.             { // In a network game, force all players to be alive
  537.                 players[i].playerstate = PST_REBORN;
  538.             }
  539.             if(!deathmatch)
  540.             { // Cooperative net-play, retain keys and weapons
  541.                 oldKeys = players[i].keys;
  542.                 oldPieces = players[i].pieces;
  543.                 for(j = 0; j < NUMWEAPONS; j++)
  544.                 {
  545.                     oldWeaponowned[j] = players[i].weaponowned[j];
  546.                 }
  547.             }
  548.         }
  549.         playerWasReborn = (players[i].playerstate == PST_REBORN);
  550.         if(deathmatch)
  551.         {
  552.             memset(players[i].frags, 0, sizeof(players[i].frags));
  553.             mobj = P_SpawnMobj(playerstarts[0][i].x<<16,
  554.                 playerstarts[0][i].y<<16, 0, MT_PLAYER_FIGHTER);
  555.             players[i].mo = mobj;
  556.             G_DeathMatchSpawnPlayer(i);
  557.             P_RemoveMobj(mobj);
  558.         }
  559.         else
  560.         {
  561.             P_SpawnPlayer(&playerstarts[position][i]);
  562.         }
  563.  
  564.         if(playerWasReborn && netgame && !deathmatch)
  565.         { // Restore keys and weapons when reborn in co-op
  566.             players[i].keys = oldKeys;
  567.             players[i].pieces = oldPieces;
  568.             for(bestWeapon = 0, j = 0; j < NUMWEAPONS; j++)
  569.             {
  570.                 if(oldWeaponowned[j])
  571.                 {
  572.                     bestWeapon = j;
  573.                     players[i].weaponowned[j] = true;
  574.                 }
  575.             }
  576.             players[i].mana[MANA_1] = 25;
  577.             players[i].mana[MANA_2] = 25;
  578.             if(bestWeapon)
  579.             { // Bring up the best weapon
  580.                 players[i].pendingweapon = bestWeapon;
  581.             }
  582.         }
  583.  
  584.         if(targetPlayerMobj == NULL)
  585.         { // The poor sap
  586.             targetPlayerMobj = players[i].mo;
  587.         }
  588.     }
  589.     randomclass = rClass;
  590.  
  591.     // Redirect anything targeting a player mobj
  592.     if(TargetPlayerAddrs)
  593.     {
  594.         for(i = 0; i < TargetPlayerCount; i++)
  595.         {
  596.             *TargetPlayerAddrs[i] = (int)targetPlayerMobj;
  597.         }
  598.         Z_Free(TargetPlayerAddrs);
  599.     }
  600.  
  601.     // Destroy all things touching players
  602.     for(i = 0; i < MAXPLAYERS; i++)
  603.     {
  604.         if(playeringame[i])
  605.         {
  606.             P_TeleportMove(players[i].mo, players[i].mo->x,
  607.                 players[i].mo->y);
  608.         }
  609.     }
  610.  
  611.     // Restore trashed globals
  612.     inv_ptr = inventoryPtr;
  613.     curpos = currentInvPos;
  614.  
  615.     // Launch waiting scripts
  616.     if(!deathmatch)
  617.     {
  618.         P_CheckACSStore();
  619.     }
  620.  
  621.     // For single play, save immediately into the reborn slot
  622.     if(!netgame)
  623.     {
  624.         SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION);
  625.     }
  626. }
  627.  
  628. //==========================================================================
  629. //
  630. // SV_GetRebornSlot
  631. //
  632. //==========================================================================
  633.  
  634. int SV_GetRebornSlot(void)
  635. {
  636.     return(REBORN_SLOT);
  637. }
  638.  
  639. //==========================================================================
  640. //
  641. // SV_RebornSlotAvailable
  642. //
  643. // Returns true if the reborn slot is available.
  644. //
  645. //==========================================================================
  646.  
  647. boolean SV_RebornSlotAvailable(void)
  648. {
  649.     char fileName[100];
  650.  
  651.     sprintf(fileName, "%shex%d.hxs", SavePath, REBORN_SLOT);
  652.     return ExistingFile(fileName);
  653. }
  654.  
  655. //==========================================================================
  656. //
  657. // SV_LoadMap
  658. //
  659. //==========================================================================
  660.  
  661. void SV_LoadMap(void)
  662. {
  663.     char fileName[100];
  664.  
  665.     // Load a base level
  666.     G_InitNew(gameskill, gameepisode, gamemap);
  667.  
  668.     // Remove all thinkers
  669.     RemoveAllThinkers();
  670.  
  671.     // Create the name
  672.     sprintf(fileName, "%shex6%02d.hxs", SavePath, gamemap);
  673.  
  674.     // Load the file
  675.     M_ReadFile(fileName, &SaveBuffer);
  676.     SavePtr.b = SaveBuffer;
  677.  
  678.     AssertSegment(ASEG_MAP_HEADER);
  679.  
  680.     // Read the level timer
  681.     leveltime = GET_LONG;
  682.  
  683.     UnarchiveWorld();
  684.     UnarchivePolyobjs();
  685.     UnarchiveMobjs();
  686.     UnarchiveThinkers();
  687.     UnarchiveScripts();
  688.     UnarchiveSounds();
  689.     UnarchiveMisc();
  690.  
  691.     AssertSegment(ASEG_END);
  692.  
  693.     // Free mobj list and save buffer
  694.     Z_Free(MobjList);
  695.     Z_Free(SaveBuffer);
  696. }
  697.  
  698. //==========================================================================
  699. //
  700. // SV_InitBaseSlot
  701. //
  702. //==========================================================================
  703.  
  704. void SV_InitBaseSlot(void)
  705. {
  706.     ClearSaveSlot(BASE_SLOT);
  707. }
  708.  
  709. //==========================================================================
  710. //
  711. // ArchivePlayers
  712. //
  713. //==========================================================================
  714.  
  715. static void ArchivePlayers(void)
  716. {
  717.     int i;
  718.     int j;
  719.     player_t tempPlayer;
  720.  
  721.     StreamOutLong(ASEG_PLAYERS);
  722.     for(i = 0; i < MAXPLAYERS; i++)
  723.     {
  724.         StreamOutByte(playeringame[i]);
  725.     }
  726.     for(i = 0; i < MAXPLAYERS; i++)
  727.     {
  728.         if(!playeringame[i])
  729.         {
  730.             continue;
  731.         }
  732.         StreamOutByte(PlayerClass[i]);
  733.         tempPlayer = players[i];
  734.         for(j = 0; j < NUMPSPRITES; j++)
  735.         {
  736.             if(tempPlayer.psprites[j].state)
  737.             {
  738.                 tempPlayer.psprites[j].state =
  739.                     (state_t *)(tempPlayer.psprites[j].state-states);
  740.             }
  741.         }
  742.         StreamOutBuffer(&tempPlayer, sizeof(player_t));
  743.     }
  744. }
  745.  
  746. //==========================================================================
  747. //
  748. // UnarchivePlayers
  749. //
  750. //==========================================================================
  751.  
  752. static void UnarchivePlayers(void)
  753. {
  754.     int i, j;
  755.  
  756.     AssertSegment(ASEG_PLAYERS);
  757.     for(i = 0; i < MAXPLAYERS; i++)
  758.     {
  759.         playeringame[i] = GET_BYTE;
  760.     }
  761.     for(i = 0; i < MAXPLAYERS; i++)
  762.     {
  763.         if(!playeringame[i])
  764.         {
  765.             continue;
  766.         }
  767.         PlayerClass[i] = GET_BYTE;
  768.         memcpy(&players[i], SavePtr.b, sizeof(player_t));
  769.         SavePtr.b += sizeof(player_t);
  770.         players[i].mo = NULL; // Will be set when unarc thinker
  771.         P_ClearMessage(&players[i]);
  772.         players[i].attacker = NULL;
  773.         players[i].poisoner = NULL;
  774.         for(j = 0; j < NUMPSPRITES; j++)
  775.         {
  776.             if(players[i].psprites[j].state)
  777.             {
  778.                 players[i].psprites[j].state =
  779.                     &states[(int)players[i].psprites[j].state];
  780.             }
  781.         }
  782.     }
  783. }
  784.  
  785. //==========================================================================
  786. //
  787. // ArchiveWorld
  788. //
  789. //==========================================================================
  790.  
  791. static void ArchiveWorld(void)
  792. {
  793.     int i;
  794.     int j;
  795.     sector_t *sec;
  796.     line_t *li;
  797.     side_t *si;
  798.  
  799.     StreamOutLong(ASEG_WORLD);
  800.     for(i = 0, sec = sectors; i < numsectors; i++, sec++)
  801.     {
  802.         StreamOutWord(sec->floorheight>>FRACBITS);
  803.         StreamOutWord(sec->ceilingheight>>FRACBITS);
  804.         StreamOutWord(sec->floorpic);
  805.         StreamOutWord(sec->ceilingpic);
  806.         StreamOutWord(sec->lightlevel);
  807.         StreamOutWord(sec->special);
  808.         StreamOutWord(sec->tag);
  809.         StreamOutWord(sec->seqType);
  810.     }
  811.     for(i = 0, li = lines; i < numlines; i++, li++)
  812.     {
  813.         StreamOutWord(li->flags);
  814.         StreamOutByte(li->special);
  815.         StreamOutByte(li->arg1);
  816.         StreamOutByte(li->arg2);
  817.         StreamOutByte(li->arg3);
  818.         StreamOutByte(li->arg4);
  819.         StreamOutByte(li->arg5);
  820.         for(j = 0; j < 2; j++)
  821.         {
  822.             if(li->sidenum[j] == -1)
  823.             {
  824.                 continue;
  825.             }
  826.             si = &sides[li->sidenum[j]];
  827.             StreamOutWord(si->textureoffset>>FRACBITS);
  828.             StreamOutWord(si->rowoffset>>FRACBITS);
  829.             StreamOutWord(si->toptexture);
  830.             StreamOutWord(si->bottomtexture);
  831.             StreamOutWord(si->midtexture);
  832.         }
  833.     }
  834. }
  835.  
  836. //==========================================================================
  837. //
  838. // UnarchiveWorld
  839. //
  840. //==========================================================================
  841.  
  842. static void UnarchiveWorld(void)
  843. {
  844.     int i;
  845.     int j;
  846.     sector_t *sec;
  847.     line_t *li;
  848.     side_t *si;
  849.  
  850.     AssertSegment(ASEG_WORLD);
  851.     for(i = 0, sec = sectors; i < numsectors; i++, sec++)
  852.     {
  853.         sec->floorheight = GET_WORD<<FRACBITS;
  854.         sec->ceilingheight = GET_WORD<<FRACBITS;
  855.         sec->floorpic = GET_WORD;
  856.         sec->ceilingpic = GET_WORD;
  857.         sec->lightlevel = GET_WORD;
  858.         sec->special = GET_WORD;
  859.         sec->tag = GET_WORD;
  860.         sec->seqType = GET_WORD;
  861.         sec->specialdata = 0;
  862.         sec->soundtarget = 0;
  863.     }
  864.     for(i = 0, li = lines; i < numlines; i++, li++)
  865.     {
  866.         li->flags = GET_WORD;
  867.         li->special = GET_BYTE;
  868.         li->arg1 = GET_BYTE;
  869.         li->arg2 = GET_BYTE;
  870.         li->arg3 = GET_BYTE;
  871.         li->arg4 = GET_BYTE;
  872.         li->arg5 = GET_BYTE;
  873.         for(j = 0; j < 2; j++)
  874.         {
  875.             if(li->sidenum[j] == -1)
  876.             {
  877.                 continue;
  878.             }
  879.             si = &sides[li->sidenum[j]];
  880.             si->textureoffset = GET_WORD<<FRACBITS;
  881.             si->rowoffset = GET_WORD<<FRACBITS;
  882.             si->toptexture = GET_WORD;
  883.             si->bottomtexture = GET_WORD;
  884.             si->midtexture = GET_WORD;
  885.         }
  886.     }
  887. }
  888.  
  889. //==========================================================================
  890. //
  891. // SetMobjArchiveNums
  892. //
  893. // Sets the archive numbers in all mobj structs.  Also sets the MobjCount
  894. // global.  Ignores player mobjs if SavingPlayers is false.
  895. //
  896. //==========================================================================
  897.  
  898. static void SetMobjArchiveNums(void)
  899. {
  900.     mobj_t *mobj;
  901.     thinker_t *thinker;
  902.  
  903.     MobjCount = 0;
  904.     for(thinker = thinkercap.next; thinker != &thinkercap;
  905.         thinker = thinker->next)
  906.     {
  907.         if(thinker->function == P_MobjThinker)
  908.         {
  909.             mobj = (mobj_t *)thinker;
  910.             if(mobj->player && !SavingPlayers)
  911.             { // Skipping player mobjs
  912.                 continue;
  913.             }
  914.             mobj->archiveNum = MobjCount++;
  915.         }
  916.     }
  917. }
  918.  
  919. //==========================================================================
  920. //
  921. // ArchiveMobjs
  922. //
  923. //==========================================================================
  924.  
  925. static void ArchiveMobjs(void)
  926. {
  927.     int count;
  928.     thinker_t *thinker;
  929.     mobj_t tempMobj;
  930.  
  931.     StreamOutLong(ASEG_MOBJS);
  932.     StreamOutLong(MobjCount);
  933.     count = 0;
  934.     for(thinker = thinkercap.next; thinker != &thinkercap;
  935.         thinker = thinker->next)
  936.     {
  937.         if(thinker->function != P_MobjThinker)
  938.         { // Not a mobj thinker
  939.             continue;
  940.         }
  941.         if(((mobj_t *)thinker)->player && !SavingPlayers)
  942.         { // Skipping player mobjs
  943.             continue;
  944.         }
  945.         count++;
  946.         memcpy(&tempMobj, thinker, sizeof(mobj_t));
  947.         MangleMobj(&tempMobj);
  948.         StreamOutBuffer(&tempMobj, sizeof(mobj_t));
  949.     }
  950.     if(count != MobjCount)
  951.     {
  952.         I_Error("ArchiveMobjs: bad mobj count");
  953.     }
  954. }
  955.  
  956. //==========================================================================
  957. //
  958. // UnarchiveMobjs
  959. //
  960. //==========================================================================
  961.  
  962. static void UnarchiveMobjs(void)
  963. {
  964.     int i;
  965.     mobj_t *mobj;
  966.  
  967.     AssertSegment(ASEG_MOBJS);
  968.     TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS*sizeof(int *),
  969.         PU_STATIC, NULL);
  970.     TargetPlayerCount = 0;
  971.     MobjCount = GET_LONG;
  972.     MobjList = Z_Malloc(MobjCount*sizeof(mobj_t *), PU_STATIC, NULL);
  973.     for(i = 0; i < MobjCount; i++)
  974.     {
  975.         MobjList[i] = Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL);
  976.     }
  977.     for(i = 0; i < MobjCount; i++)
  978.     {
  979.         mobj = MobjList[i];
  980.         memcpy(mobj, SavePtr.b, sizeof(mobj_t));
  981.         SavePtr.b += sizeof(mobj_t);
  982.         mobj->thinker.function = P_MobjThinker;
  983.         RestoreMobj(mobj);
  984.         P_AddThinker(&mobj->thinker);
  985.     }
  986.     P_CreateTIDList();
  987.     P_InitCreatureCorpseQueue(true); // true = scan for corpses
  988. }
  989.  
  990. //==========================================================================
  991. //
  992. // MangleMobj
  993. //
  994. //==========================================================================
  995.  
  996. static void MangleMobj(mobj_t *mobj)
  997. {
  998.     boolean corpse;
  999.  
  1000.     corpse = mobj->flags&MF_CORPSE;
  1001.     mobj->state = (state_t *)(mobj->state-states);
  1002.     if(mobj->player)
  1003.     {
  1004.         mobj->player = (player_t *)((mobj->player-players)+1);
  1005.     }
  1006.     if(corpse)
  1007.     {
  1008.         mobj->target = (mobj_t *)MOBJ_NULL;
  1009.     }
  1010.     else
  1011.     {
  1012.         mobj->target = (mobj_t *)GetMobjNum(mobj->target);
  1013.     }
  1014.     switch(mobj->type)
  1015.     {
  1016.         // Just special1
  1017.         case MT_BISH_FX:
  1018.         case MT_HOLY_FX:
  1019.         case MT_DRAGON:
  1020.         case MT_THRUSTFLOOR_UP:
  1021.         case MT_THRUSTFLOOR_DOWN:
  1022.         case MT_MINOTAUR:
  1023.         case MT_SORCFX1:
  1024.         case MT_MSTAFF_FX2:
  1025.             if(corpse)
  1026.             {
  1027.                 mobj->special1 = MOBJ_NULL;
  1028.             }
  1029.             else
  1030.             {
  1031.                 mobj->special1 = GetMobjNum((mobj_t *)mobj->special1);
  1032.             }
  1033.             break;
  1034.  
  1035.         // Just special2
  1036.         case MT_LIGHTNING_FLOOR:
  1037.         case MT_LIGHTNING_ZAP:
  1038.             if(corpse)
  1039.             {
  1040.                 mobj->special2 = MOBJ_NULL;
  1041.             }
  1042.             else
  1043.             {
  1044.                 mobj->special2 = GetMobjNum((mobj_t *)mobj->special2);
  1045.             }
  1046.             break;
  1047.  
  1048.         // Both special1 and special2
  1049.         case MT_HOLY_TAIL:
  1050.         case MT_LIGHTNING_CEILING:
  1051.             if(corpse)
  1052.             {
  1053.                 mobj->special1 = MOBJ_NULL;
  1054.                 mobj->special2 = MOBJ_NULL;
  1055.             }
  1056.             else
  1057.             {
  1058.                 mobj->special1 = GetMobjNum((mobj_t *)mobj->special1);
  1059.                 mobj->special2 = GetMobjNum((mobj_t *)mobj->special2);
  1060.             }
  1061.             break;
  1062.  
  1063.         // Miscellaneous
  1064.         case MT_KORAX:
  1065.             mobj->special1 = 0; // Searching index
  1066.             break;
  1067.  
  1068.         default:
  1069.             break;
  1070.     }
  1071. }
  1072.  
  1073. //==========================================================================
  1074. //
  1075. // GetMobjNum
  1076. //
  1077. //==========================================================================
  1078.  
  1079. static int GetMobjNum(mobj_t *mobj)
  1080. {
  1081.     if(mobj == NULL)
  1082.     {
  1083.         return MOBJ_NULL;
  1084.     }
  1085.     if(mobj->player && !SavingPlayers)
  1086.     {
  1087.         return MOBJ_XX_PLAYER;
  1088.     }
  1089.     return mobj->archiveNum;
  1090. }
  1091.  
  1092. //==========================================================================
  1093. //
  1094. // RestoreMobj
  1095. //
  1096. //==========================================================================
  1097.  
  1098. static void RestoreMobj(mobj_t *mobj)
  1099. {
  1100.     mobj->state = &states[(int)mobj->state];
  1101.     if(mobj->player)
  1102.     {
  1103.         mobj->player = &players[(int)mobj->player-1];
  1104.         mobj->player->mo = mobj;
  1105.     }
  1106.     P_SetThingPosition(mobj);
  1107.     mobj->info = &mobjinfo[mobj->type];
  1108.     mobj->floorz = mobj->subsector->sector->floorheight;
  1109.     mobj->ceilingz = mobj->subsector->sector->ceilingheight;
  1110.     SetMobjPtr((int *)&mobj->target);
  1111.     switch(mobj->type)
  1112.     {
  1113.         // Just special1
  1114.         case MT_BISH_FX:
  1115.         case MT_HOLY_FX:
  1116.         case MT_DRAGON:
  1117.         case MT_THRUSTFLOOR_UP:
  1118.         case MT_THRUSTFLOOR_DOWN:
  1119.         case MT_MINOTAUR:
  1120.         case MT_SORCFX1:
  1121.             SetMobjPtr(&mobj->special1);
  1122.             break;
  1123.  
  1124.         // Just special2
  1125.         case MT_LIGHTNING_FLOOR:
  1126.         case MT_LIGHTNING_ZAP:
  1127.             SetMobjPtr(&mobj->special2);
  1128.             break;
  1129.  
  1130.         // Both special1 and special2
  1131.         case MT_HOLY_TAIL:
  1132.         case MT_LIGHTNING_CEILING:
  1133.             SetMobjPtr(&mobj->special1);
  1134.             SetMobjPtr(&mobj->special2);
  1135.             break;
  1136.  
  1137.         default:
  1138.             break;
  1139.     }
  1140. }
  1141.  
  1142. //==========================================================================
  1143. //
  1144. // SetMobjPtr
  1145. //
  1146. //==========================================================================
  1147.  
  1148. static void SetMobjPtr(int *archiveNum)
  1149. {
  1150.     if(*archiveNum == MOBJ_NULL)
  1151.     {
  1152.         *archiveNum = 0;
  1153.         return;
  1154.     }
  1155.     if(*archiveNum == MOBJ_XX_PLAYER)
  1156.     {
  1157.         if(TargetPlayerCount == MAX_TARGET_PLAYERS)
  1158.         {
  1159.             I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS");
  1160.         }
  1161.         TargetPlayerAddrs[TargetPlayerCount++] = archiveNum;
  1162.         *archiveNum = 0;
  1163.         return;
  1164.     }
  1165.     *archiveNum = (int)MobjList[*archiveNum];
  1166. }
  1167.  
  1168. //==========================================================================
  1169. //
  1170. // ArchiveThinkers
  1171. //
  1172. //==========================================================================
  1173.  
  1174. static void ArchiveThinkers(void)
  1175. {
  1176.     thinker_t *thinker;
  1177.     thinkInfo_t *info;
  1178.     byte buffer[MAX_THINKER_SIZE];
  1179.  
  1180.     StreamOutLong(ASEG_THINKERS);
  1181.     for(thinker = thinkercap.next; thinker != &thinkercap;
  1182.         thinker = thinker->next)
  1183.     {
  1184.         for(info = ThinkerInfo; info->tClass != TC_NULL; info++)
  1185.         {
  1186.             if(thinker->function == info->thinkerFunc)
  1187.             {
  1188.                 StreamOutByte(info->tClass);
  1189.                 memcpy(buffer, thinker, info->size);
  1190.                 if(info->mangleFunc)
  1191.                 {
  1192.                     info->mangleFunc(buffer);
  1193.                 }
  1194.                 StreamOutBuffer(buffer, info->size);
  1195.                 break;
  1196.             }
  1197.         }
  1198.     }
  1199.     // Add a termination marker
  1200.     StreamOutByte(TC_NULL);
  1201. }
  1202.  
  1203. //==========================================================================
  1204. //
  1205. // UnarchiveThinkers
  1206. //
  1207. //==========================================================================
  1208.  
  1209. static void UnarchiveThinkers(void)
  1210. {
  1211.     int tClass;
  1212.     thinker_t *thinker;
  1213.     thinkInfo_t *info;
  1214.  
  1215.     AssertSegment(ASEG_THINKERS);
  1216.     while((tClass = GET_BYTE) != TC_NULL)
  1217.     {
  1218.         for(info = ThinkerInfo; info->tClass != TC_NULL; info++)
  1219.         {
  1220.             if(tClass == info->tClass)
  1221.             {
  1222.                 thinker = Z_Malloc(info->size, PU_LEVEL, NULL);
  1223.                 memcpy(thinker, SavePtr.b, info->size);
  1224.                 SavePtr.b += info->size;
  1225.                 thinker->function = info->thinkerFunc;
  1226.                 if(info->restoreFunc)
  1227.                 {
  1228.                     info->restoreFunc(thinker);
  1229.                 }
  1230.                 P_AddThinker(thinker);
  1231.                 break;
  1232.             }
  1233.         }
  1234.         if(info->tClass == TC_NULL)
  1235.         {
  1236.             I_Error("UnarchiveThinkers: Unknown tClass %d in "
  1237.                 "savegame", tClass);
  1238.         }
  1239.     }
  1240. }
  1241.  
  1242. //==========================================================================
  1243. //
  1244. // MangleSSThinker
  1245. //
  1246. //==========================================================================
  1247.  
  1248. static void MangleSSThinker(ssthinker_t *sst)
  1249. {
  1250.     sst->sector = (sector_t *)(sst->sector-sectors);
  1251. }
  1252.  
  1253. //==========================================================================
  1254. //
  1255. // RestoreSSThinker
  1256. //
  1257. //==========================================================================
  1258.  
  1259. static void RestoreSSThinker(ssthinker_t *sst)
  1260. {
  1261.     sst->sector = §ors[(int)sst->sector];
  1262.     sst->sector->specialdata = sst->thinker.function;
  1263. }
  1264.  
  1265. //==========================================================================
  1266. //
  1267. // RestoreSSThinkerNoSD
  1268. //
  1269. //==========================================================================
  1270.  
  1271. static void RestoreSSThinkerNoSD(ssthinker_t *sst)
  1272. {
  1273.     sst->sector = §ors[(int)sst->sector];
  1274. }
  1275.  
  1276. //==========================================================================
  1277. //
  1278. // MangleScript
  1279. //
  1280. //==========================================================================
  1281.  
  1282. static void MangleScript(acs_t *script)
  1283. {
  1284.     script->ip = (int *)((int)(script->ip)-(int)ActionCodeBase);
  1285.     script->line = script->line ?
  1286.         (line_t *)(script->line-lines) : (line_t *)-1;
  1287.     script->activator = (mobj_t *)GetMobjNum(script->activator);
  1288. }
  1289.  
  1290. //==========================================================================
  1291. //
  1292. // RestoreScript
  1293. //
  1294. //==========================================================================
  1295.  
  1296. static void RestoreScript(acs_t *script)
  1297. {
  1298.     script->ip = (int *)(ActionCodeBase+(int)script->ip);
  1299.     if((int)script->line == -1)
  1300.     {
  1301.         script->line = NULL;
  1302.     }
  1303.     else
  1304.     {
  1305.         script->line = &lines[(int)script->line];
  1306.     }
  1307.     SetMobjPtr((int *)&script->activator);
  1308. }
  1309.  
  1310. //==========================================================================
  1311. //
  1312. // RestorePlatRaise
  1313. //
  1314. //==========================================================================
  1315.  
  1316. static void RestorePlatRaise(plat_t *plat)
  1317. {
  1318.     plat->sector = §ors[(int)plat->sector];
  1319.     plat->sector->specialdata = T_PlatRaise;
  1320.     P_AddActivePlat(plat);
  1321. }
  1322.  
  1323. //==========================================================================
  1324. //
  1325. // RestoreMoveCeiling
  1326. //
  1327. //==========================================================================
  1328.  
  1329. static void RestoreMoveCeiling(ceiling_t *ceiling)
  1330. {
  1331.     ceiling->sector = §ors[(int)ceiling->sector];
  1332.     ceiling->sector->specialdata = T_MoveCeiling;
  1333.     P_AddActiveCeiling(ceiling);
  1334. }
  1335.  
  1336. //==========================================================================
  1337. //
  1338. // ArchiveScripts
  1339. //
  1340. //==========================================================================
  1341.  
  1342. static void ArchiveScripts(void)
  1343. {
  1344.     int i;
  1345.  
  1346.     StreamOutLong(ASEG_SCRIPTS);
  1347.     for(i = 0; i < ACScriptCount; i++)
  1348.     {
  1349.         StreamOutWord(ACSInfo[i].state);
  1350.         StreamOutWord(ACSInfo[i].waitValue);
  1351.     }
  1352.     StreamOutBuffer(MapVars, sizeof(MapVars));
  1353. }
  1354.  
  1355. //==========================================================================
  1356. //
  1357. // UnarchiveScripts
  1358. //
  1359. //==========================================================================
  1360.  
  1361. static void UnarchiveScripts(void)
  1362. {
  1363.     int i;
  1364.  
  1365.     AssertSegment(ASEG_SCRIPTS);
  1366.     for(i = 0; i < ACScriptCount; i++)
  1367.     {
  1368.         ACSInfo[i].state = GET_WORD;
  1369.         ACSInfo[i].waitValue = GET_WORD;
  1370.     }
  1371.     memcpy(MapVars, SavePtr.b, sizeof(MapVars));
  1372.     SavePtr.b += sizeof(MapVars);
  1373. }
  1374.  
  1375. //==========================================================================
  1376. //
  1377. // ArchiveMisc
  1378. //
  1379. //==========================================================================
  1380.  
  1381. static void ArchiveMisc(void)
  1382. {
  1383.     int ix;
  1384.  
  1385.     StreamOutLong(ASEG_MISC);
  1386.     for (ix=0; ix<MAXPLAYERS; ix++)
  1387.     {
  1388.         StreamOutLong(localQuakeHappening[ix]);
  1389.     }
  1390. }
  1391.  
  1392. //==========================================================================
  1393. //
  1394. // UnarchiveMisc
  1395. //
  1396. //==========================================================================
  1397.  
  1398. static void UnarchiveMisc(void)
  1399. {
  1400.     int ix;
  1401.  
  1402.     AssertSegment(ASEG_MISC);
  1403.     for (ix=0; ix<MAXPLAYERS; ix++)
  1404.     {
  1405.         localQuakeHappening[ix] = GET_LONG;
  1406.     }
  1407. }
  1408.  
  1409. //==========================================================================
  1410. //
  1411. // RemoveAllThinkers
  1412. //
  1413. //==========================================================================
  1414.  
  1415. static void RemoveAllThinkers(void)
  1416. {
  1417.     thinker_t *thinker;
  1418.     thinker_t *nextThinker;
  1419.  
  1420.     thinker = thinkercap.next;
  1421.     while(thinker != &thinkercap)
  1422.     {
  1423.         nextThinker = thinker->next;
  1424.         if(thinker->function == P_MobjThinker)
  1425.         {
  1426.             P_RemoveMobj((mobj_t *)thinker);
  1427.         }
  1428.         else
  1429.         {
  1430.             Z_Free(thinker);
  1431.         }
  1432.         thinker = nextThinker;
  1433.     }
  1434.     P_InitThinkers();
  1435. }
  1436.  
  1437. //==========================================================================
  1438. //
  1439. // ArchiveSounds
  1440. //
  1441. //==========================================================================
  1442.  
  1443. static void ArchiveSounds(void)
  1444. {
  1445.     seqnode_t *node;
  1446.     sector_t *sec;
  1447.     int difference;
  1448.     int i;
  1449.  
  1450.     StreamOutLong(ASEG_SOUNDS);
  1451.  
  1452.     // Save the sound sequences
  1453.     StreamOutLong(ActiveSequences);
  1454.     for(node = SequenceListHead; node; node = node->next)
  1455.     {
  1456.         StreamOutLong(node->sequence);
  1457.         StreamOutLong(node->delayTics);
  1458.         StreamOutLong(node->volume);
  1459.         StreamOutLong(SN_GetSequenceOffset(node->sequence,
  1460.             node->sequencePtr));
  1461.         StreamOutLong(node->currentSoundID);
  1462.         for(i = 0; i < po_NumPolyobjs; i++)
  1463.         {
  1464.             if(node->mobj == (mobj_t *)&polyobjs[i].startSpot)
  1465.             {
  1466.                 break;
  1467.             }
  1468.         }
  1469.         if(i == po_NumPolyobjs)
  1470.         { // Sound is attached to a sector, not a polyobj
  1471.             sec = R_PointInSubsector(node->mobj->x, node->mobj->y)->sector;
  1472.             difference = (int)((byte *)sec
  1473.                 -(byte *)§ors[0])/sizeof(sector_t);
  1474.             StreamOutLong(0); // 0 -- sector sound origin
  1475.         }
  1476.         else
  1477.         {
  1478.             StreamOutLong(1); // 1 -- polyobj sound origin
  1479.             difference = i;
  1480.         }
  1481.         StreamOutLong(difference);
  1482.     }
  1483. }
  1484.  
  1485. //==========================================================================
  1486. //
  1487. // UnarchiveSounds
  1488. //
  1489. //==========================================================================
  1490.  
  1491. static void UnarchiveSounds(void)
  1492. {
  1493.     int i;
  1494.     int numSequences;
  1495.     int sequence;
  1496.     int delayTics;
  1497.     int volume;
  1498.     int seqOffset;
  1499.     int soundID;
  1500.     int polySnd;
  1501.     int secNum;
  1502.     mobj_t *sndMobj;
  1503.  
  1504.     AssertSegment(ASEG_SOUNDS);
  1505.  
  1506.     // Reload and restart all sound sequences
  1507.     numSequences = GET_LONG;
  1508.     i = 0;
  1509.     while(i < numSequences)
  1510.     {
  1511.         sequence = GET_LONG;
  1512.         delayTics = GET_LONG;
  1513.         volume = GET_LONG;
  1514.         seqOffset = GET_LONG;
  1515.  
  1516.         soundID = GET_LONG;
  1517.         polySnd = GET_LONG;
  1518.         secNum = GET_LONG;
  1519.         if(!polySnd)
  1520.         {
  1521.             sndMobj = (mobj_t *)§ors[secNum].soundorg;
  1522.         }
  1523.         else
  1524.         {
  1525.             sndMobj = (mobj_t *)&polyobjs[secNum].startSpot;
  1526.         }
  1527.         SN_StartSequence(sndMobj, sequence);
  1528.         SN_ChangeNodeData(i, seqOffset, delayTics, volume, soundID);
  1529.         i++;
  1530.     }
  1531. }
  1532.  
  1533. //==========================================================================
  1534. //
  1535. // ArchivePolyobjs
  1536. //
  1537. //==========================================================================
  1538.  
  1539. static void ArchivePolyobjs(void)
  1540. {
  1541.     int i;
  1542.  
  1543.     StreamOutLong(ASEG_POLYOBJS);
  1544.     StreamOutLong(po_NumPolyobjs);
  1545.     for(i = 0; i < po_NumPolyobjs; i++)
  1546.     {
  1547.         StreamOutLong(polyobjs[i].tag);
  1548.         StreamOutLong(polyobjs[i].angle);
  1549.         StreamOutLong(polyobjs[i].startSpot.x);
  1550.         StreamOutLong(polyobjs[i].startSpot.y);
  1551.       }
  1552. }
  1553.  
  1554. //==========================================================================
  1555. //
  1556. // UnarchivePolyobjs
  1557. //
  1558. //==========================================================================
  1559.  
  1560. static void UnarchivePolyobjs(void)
  1561. {
  1562.     int i;
  1563.     fixed_t deltaX;
  1564.     fixed_t deltaY;
  1565.  
  1566.     AssertSegment(ASEG_POLYOBJS);
  1567.     if(GET_LONG != po_NumPolyobjs)
  1568.     {
  1569.         I_Error("UnarchivePolyobjs: Bad polyobj count");
  1570.     }
  1571.     for(i = 0; i < po_NumPolyobjs; i++)
  1572.     {
  1573.         if(GET_LONG != polyobjs[i].tag)
  1574.         {
  1575.             I_Error("UnarchivePolyobjs: Invalid polyobj tag");
  1576.         }
  1577.         PO_RotatePolyobj(polyobjs[i].tag, (angle_t)GET_LONG);
  1578.         deltaX = GET_LONG-polyobjs[i].startSpot.x;
  1579.         deltaY = GET_LONG-polyobjs[i].startSpot.y;
  1580.         PO_MovePolyobj(polyobjs[i].tag, deltaX, deltaY);
  1581.     }
  1582. }
  1583.  
  1584. //==========================================================================
  1585. //
  1586. // AssertSegment
  1587. //
  1588. //==========================================================================
  1589.  
  1590. static void AssertSegment(gameArchiveSegment_t segType)
  1591. {
  1592.     if(GET_LONG != segType)
  1593.     {
  1594.         I_Error("Corrupt save game: Segment [%d] failed alignment check",
  1595.             segType);
  1596.     }
  1597. }
  1598.  
  1599. //==========================================================================
  1600. //
  1601. // ClearSaveSlot
  1602. //
  1603. // Deletes all save game files associated with a slot number.
  1604. //
  1605. //==========================================================================
  1606.  
  1607. static void ClearSaveSlot(int slot)
  1608. {
  1609.     int i;
  1610.     char fileName[100];
  1611.  
  1612.     for(i = 0; i < MAX_MAPS; i++)
  1613.     {
  1614.         sprintf(fileName, "%shex%d%02d.hxs", SavePath, slot, i);
  1615.         remove(fileName);
  1616.     }
  1617.     sprintf(fileName, "%shex%d.hxs", SavePath, slot);
  1618.     remove(fileName);
  1619. }
  1620.  
  1621. //==========================================================================
  1622. //
  1623. // CopySaveSlot
  1624. //
  1625. // Copies all the save game files from one slot to another.
  1626. //
  1627. //==========================================================================
  1628.  
  1629. static void CopySaveSlot(int sourceSlot, int destSlot)
  1630. {
  1631.     int i;
  1632.     char sourceName[100];
  1633.     char destName[100];
  1634.  
  1635.     for(i = 0; i < MAX_MAPS; i++)
  1636.     {
  1637.         sprintf(sourceName, "%shex%d%02d.hxs", SavePath, sourceSlot, i);
  1638.         if(ExistingFile(sourceName))
  1639.         {
  1640.             sprintf(destName, "%shex%d%02d.hxs", SavePath, destSlot, i);
  1641.             CopyFile(sourceName, destName);
  1642.         }
  1643.     }
  1644.     sprintf(sourceName, "%shex%d.hxs", SavePath, sourceSlot);
  1645.     if(ExistingFile(sourceName))
  1646.     {
  1647.         sprintf(destName, "%shex%d.hxs", SavePath, destSlot);
  1648.         CopyFile(sourceName, destName);
  1649.     }
  1650. }
  1651.  
  1652. //==========================================================================
  1653. //
  1654. // CopyFile
  1655. //
  1656. //==========================================================================
  1657.  
  1658. static void CopyFile(char *sourceName, char *destName)
  1659. {
  1660.     int length;
  1661.     byte *buffer;
  1662.  
  1663.     length = M_ReadFile(sourceName, &buffer);
  1664.     M_WriteFile(destName, buffer, length);
  1665.     Z_Free(buffer);
  1666. }
  1667.  
  1668. //==========================================================================
  1669. //
  1670. // ExistingFile
  1671. //
  1672. //==========================================================================
  1673.  
  1674. static boolean ExistingFile(char *name)
  1675. {
  1676.     FILE *fp;
  1677.  
  1678.     if((fp = fopen(name, "rb")) != NULL)
  1679.     {
  1680.         fclose(fp);
  1681.         return true;
  1682.     }
  1683.     else
  1684.     {
  1685.         return false;
  1686.     }
  1687. }
  1688.  
  1689. //==========================================================================
  1690. //
  1691. // OpenStreamOut
  1692. //
  1693. //==========================================================================
  1694.  
  1695. static void OpenStreamOut(char *fileName)
  1696. {
  1697.     SavingFP = fopen(fileName, "wb");
  1698. }
  1699.  
  1700. //==========================================================================
  1701. //
  1702. // CloseStreamOut
  1703. //
  1704. //==========================================================================
  1705.  
  1706. static void CloseStreamOut(void)
  1707. {
  1708.     if(SavingFP)
  1709.     {
  1710.         fclose(SavingFP);
  1711.     }
  1712. }
  1713.  
  1714. //==========================================================================
  1715. //
  1716. // StreamOutBuffer
  1717. //
  1718. //==========================================================================
  1719.  
  1720. static void StreamOutBuffer(void *buffer, int size)
  1721. {
  1722.     fwrite(buffer, size, 1, SavingFP);
  1723. }
  1724.  
  1725. //==========================================================================
  1726. //
  1727. // StreamOutByte
  1728. //
  1729. //==========================================================================
  1730.  
  1731. static void StreamOutByte(byte val)
  1732. {
  1733.     fwrite(&val, sizeof(byte), 1, SavingFP);
  1734. }
  1735.  
  1736. //==========================================================================
  1737. //
  1738. // StreamOutWord
  1739. //
  1740. //==========================================================================
  1741.  
  1742. static void StreamOutWord(unsigned short val)
  1743. {
  1744.     fwrite(&val, sizeof(unsigned short), 1, SavingFP);
  1745. }
  1746.  
  1747. //==========================================================================
  1748. //
  1749. // StreamOutLong
  1750. //
  1751. //==========================================================================
  1752.  
  1753. static void StreamOutLong(unsigned int val)
  1754. {
  1755.     fwrite(&val, sizeof(int), 1, SavingFP);
  1756. }
  1757.